package org.mx.service.server;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.ws.rs.Path;

import org.eclipse.jetty.server.Handler;
import org.glassfish.jersey.jetty.JettyHttpContainer;
import org.glassfish.jersey.jetty.JettyHttpContainerProvider;
import org.glassfish.jersey.media.multipart.MultiPartFeature;
import org.glassfish.jersey.server.ContainerFactory;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.filter.UriConnegFilter;
import org.glassfish.jersey.server.spring.scope.RequestContextFilter;
import org.mx.StringUtils;
import org.mx.service.error.UserInterfaceServiceErrorException;
import org.mx.service.error.UserInterfaceServiceErrorException.ServiceErrors;
import org.mx.service.rest.ServerStatisticResource;
import org.mx.service.rest.UserInterfaceExceptionMapper;
import org.mx.service.rest.auth.RestAuthenticateFilter;
import org.mx.service.rest.cors.CorsFilter;
import org.mx.service.server.jmx.RestfulServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;

/**
 * 描述： 基于Jetty的Http服务的工厂类
 *
 * @author John.Peng Date time 2018/3/11 上午11:11
 */
public class RestfulServerFactory extends HttpServerFactory {
	private static final Logger logger = LoggerFactory.getLogger(RestfulServerFactory.class);

	private RestfulServerConfigBean restfulServerConfigBean;

	/**
	 * 默认的构造函数
	 *
	 * @param context                 Spring IoC上下文
	 * @param restfulServerConfigBean RESTful配置对象
	 * @param restfulServerMXBean	Restful MXBean对象
	 */
	public RestfulServerFactory(ApplicationContext context, RestfulServerConfigBean restfulServerConfigBean,
			RestfulServer restfulServerMXBean) {
		super(context, restfulServerConfigBean, restfulServerMXBean);
		this.restfulServerConfigBean = restfulServerConfigBean;
	}

	/**
	 * {@inheritDoc}
	 *
	 * @see HttpServerFactory#getHandler()
	 */
	@Override
	protected Handler getHandler() {
		String[] serverClasses = restfulServerConfigBean.getServiceClasses();
		String[] resourceBasePackages = restfulServerConfigBean.getResourceBasePackages();
		// 扫描相应的RESTful Resource
		List<Class<?>> customRegisters = super.getResourceClasses(serverClasses, resourceBasePackages, clazz -> {
			boolean result = clazz.isAnnotationPresent(Path.class);
			if (result) {
				if (logger.isDebugEnabled()) {
					logger.debug(String.format("The RESTful resource['%s'] is loaded successfully.", clazz.getName()));
				}
			} else {
				if (logger.isWarnEnabled()) {
					logger.warn(String.format("The class['%s'] is not a RESTful resource.", clazz.getName()));
				}
			}
			return result;
		});
		// 扫描配置的自定义Register
		String[] registerClasses = restfulServerConfigBean.getRegisterClasses();
		if (registerClasses != null && registerClasses.length > 0) {
			for (String className : registerClasses) {
				if (StringUtils.isBlank(className)) {
					continue;
				}
				try {
					Class<?> clazz = Class.forName(className);
					customRegisters.add(clazz);
				} catch (ClassNotFoundException ex) {
					if (logger.isErrorEnabled()) {
						logger.error(String.format("The class[%s] not found.", className), ex);
					}
					throw new UserInterfaceServiceErrorException(ServiceErrors.REST_INITIALIZE_ERROR);
				}
			}
		}
		if (customRegisters.isEmpty()) {
			if (logger.isWarnEnabled()) {
				logger.warn("There are not any restful service be defined, will not start the Http Server.");
			}
			return null;
		}

		Set<String> resourceNames = new HashSet<>();
		ResourceConfig config = new ResourceConfig();
		config.register(UriConnegFilter.class);
		resourceNames.add(UriConnegFilter.class.getName());
		config.register(JettyHttpContainerProvider.class);
		resourceNames.add(JettyHttpContainerProvider.class.getName());
		config.register(RequestContextFilter.class);
		resourceNames.add(RequestContextFilter.class.getName());
		// 注册所有的RESTful资源和自定义注册器
		customRegisters.forEach(clazz -> {
			config.register(clazz);
			resourceNames.add(clazz.getName());
		});
		// 启用服务器统计数据
		config.register(ServerStatisticResource.class);
		resourceNames.add(ServerStatisticResource.class.getName());
		// 根据需要注册跨域过滤器
		config.register(CorsFilter.class);
		resourceNames.add(CorsFilter.class.getName());
		// 注册身份令牌过滤器
		config.register(RestAuthenticateFilter.class);
		resourceNames.add(RestAuthenticateFilter.class.getName());
		// 注册通用的UserInterface异常处理类
		config.register(UserInterfaceExceptionMapper.class);
		resourceNames.add(UserInterfaceExceptionMapper.class.getName());
		// 注册Multipart
		config.register(MultiPartFeature.class);
		resourceNames.add(MultiPartFeature.class.getName());
		if (super.httpServerMXBean != null) {
			((RestfulServer) super.httpServerMXBean).setRestfulResourses(resourceNames);
		}
		/*
		 * 为了使用Spring IoC注入，需要将ApplicationContext事先注入
		 */
		config.property("contextConfig", context);
		return ContainerFactory.createContainer(JettyHttpContainer.class, config);
	}
}
